#include "IStackAllocator.h"
#include "StackAllocator.h"
#define ALLOCATOR_SIZE 1048576

#pragma once
class StackAllocatorManager:
	public Ogre::Singleton<StackAllocatorManager>
{

	std::map<Ogre::String,IStackAllocator*> levelScopeAllocatorMap;

	void * allocatorPointer;
	void * allocatorBottom;
	int allocatedMemory;

public:

	

	IStackAllocator* getLevelScopeAllocator(Ogre::String);
	void addLevelScopeAllocator(Ogre::String, IStackAllocator*);
	void resetLevelScopeAllocators();

	int getFreeMemory();
	int getAllMemory();


	static StackAllocatorManager& getSingleton(void);
    static StackAllocatorManager* getSingletonPtr(void);


	StackAllocatorManager(void);
	~StackAllocatorManager(void);


	template <class T>
	T* allocateObject(char* objectName, unsigned short SIZE)
	{
		IStackAllocator* iallocator =  getLevelScopeAllocator(objectName);

		//CommonFunctions::DebugOutputWrite("Memory used by allocators (free/all): %d / %d \n" , getFreeMemory(),  getAllMemory());
		if(iallocator!=0)
		{
			StackAllocator<T> * allocator = (StackAllocator<T>*) iallocator;

			//CommonFunctions::DebugOutputWrite("Allocated intances (allocator:free/all): %s: %d / %d \n" , objectName,allocator->getFreeObjectCount(),  allocator->getMaxObjectCount());

			return allocator->pop();
		}
		else
		{
			/*StackAllocator<T,SIZE> * allocator = static_cast<StackAllocator<T,SIZE>*>(allocatorPointer);*/
			/**((StackAllocator<T,SIZE>*)allocatorPointer) =StackAllocator<T,SIZE>();

			StackAllocator<T,SIZE> * allocator = (StackAllocator<T,SIZE>*) allocatorPointer;*/
			//*allocator = StackAllocator<T,SIZE>();


			StackAllocator<T> * allocator = new StackAllocator<T>((T*)allocatorPointer,SIZE);

			int sizeOfStackAllocator = sizeof(T)*SIZE;
			allocatorPointer = static_cast<char*>(allocatorPointer) + sizeOfStackAllocator;

			allocatedMemory+=sizeOfStackAllocator;

			//CommonFunctions::DebugOutputWrite("Allocated memory (free/all): %d / %d \n" , allocatedMemory,  ALLOCATOR_SIZE);

			addLevelScopeAllocator(objectName,allocator);

			return allocator->pop();
		}

	}
	//-------------------------------------------------------------------------------------
	template <class T>
	void freeObject(char* objectName, T* object)
	{
		IStackAllocator* iallocator =  getLevelScopeAllocator(objectName);

		//CommonFunctions::DebugOutputWrite("Memory used by allocators (free/all): %d / %d \n" , getFreeMemory(),  getAllMemory());
		//assert(iallocator!=0, "You are trying to free a non allocated object!");

		StackAllocator<T> * allocator = (StackAllocator<T>*) iallocator;

		//CommonFunctions::DebugOutputWrite("Allocated intances (allocator:free/all): %s: %d / %d \n" , objectName,allocator->getFreeObjectCount(),  allocator->getMaxObjectCount());

		return allocator->push(object);

	}


};

